package org.xxpay.pay.ctrl.payment;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.PayEnum;
import org.xxpay.core.common.domain.api.AbstractRes;
import org.xxpay.core.common.domain.api.ApiBuilder;
import org.xxpay.core.common.domain.api.SettRes;
import org.xxpay.core.common.exception.ServiceException;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.common.util.XXPayUtil;
import org.xxpay.core.entity.MchInfo;
import org.xxpay.core.entity.SettRecord;
import org.xxpay.pay.ctrl.common.BaseController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @Description: 商户结算接口
 * @author dingzhiwei jmdhappy@126.com
 * @date 2017-10-30
 * @version V1.0
 * @Copyright: www.xxpay.org
 */

@Controller
public class SettController extends BaseController {

    private final MyLog _log = MyLog.getLog(SettController.class);

    /**
     * 结算接口:
     * 1)先验证接口参数以及签名信息
     * 2)验证通过创建结算订单
     * 3)创建待审核的结算订单
     * 4)返回下单数据
     * @param request
     * @return
     */
    @RequestMapping(value = "/api/sett/create_order")
    @ResponseBody
    public AbstractRes settOrder(HttpServletRequest request) {
        _log.info("###### 开始接收商户统一结算请求 ######");
        String logPrefix = "【商户结算申请】";
        try {
            JSONObject po = getJsonParam(request);
            _log.info("{}请求参数:{}", logPrefix, po);
            JSONObject settContext = new JSONObject();
            SettRecord settRecord = null;
            // 验证参数有效性
            Object object = validateParams(po, settContext);
            if (object instanceof String) {
                _log.info("{}参数校验不通过:{}", logPrefix, object);
                return ApiBuilder.bizError(PayEnum.ERR_0014);
            }
            if (object instanceof SettRecord) settRecord = (SettRecord) object;
            if(settRecord == null) return ApiBuilder.bizError("结算申请失败");
            settRecord.setSettStatus(MchConstant.SETT_STATUS_AUDIT_ING);
            int result = commonService.settRecordService.applySett(MchConstant.SETT_INFO_TYPE_MCH,settRecord.getInfoId(), settRecord.getSettAmount(), settRecord.getBankName(), settRecord.getBankNetName(), settRecord.getAccountName(), settRecord.getAccountNo(),
                                                                                                                                    settRecord.getMchOrderNo(),settRecord.getProvince(),settRecord.getCity(),settRecord.getRemark(),MchConstant.SETT_CHANNEL_API);
            _log.info("{}创建结算记录,结果:{}", logPrefix, result);

            if(result != 1) {
                return ApiBuilder.bizError("创建结算订单失败");
            }

            SettRes settRes = ApiBuilder.buildSuccess(SettRes.class);
            settRes.setBySettRecord(settRecord);
            settRes.autoGenSign(settContext.getString("key"));
            return settRes;
        }catch (ServiceException e) {
            _log.error(e, "");
            return ApiBuilder.bizError(e.getRetEnum().getMessage());
        }catch (Exception e) {
            _log.error(e, "");
            return ApiBuilder.bizError("结算中心系统异常");
        }
    }

    /**
     * 验证创建订单请求参数,参数通过返回JSONObject对象,否则返回错误文本信息
     * @param params
     * @return
     */
    private Object validateParams(JSONObject params, JSONObject settContext) {

        //验证公共请求参数
        String commonErrorMsg = super.validateCommonParams(params);
        if(commonErrorMsg != null) return commonErrorMsg;

        // 验证请求参数,参数有问题返回错误提示
        String errorMessage;
        // 支付参数
        String infoId = params.getString("infoId");                                   //商户ID
        String mchOrderNo = params.getString("mchOrderNo");       //结算订单号
        String settAmount = params.getString("settAmount");            // 结算金额，单位分
        Byte accountType = params.getByte("accountType");              //账户类型:1-银行卡转账,2-微信转账,3-支付宝转账
        String bankName = params.getString("bankName");                //开户行名称
        String bankNetName = params.getString("bankNetName");  //开户网点名称
        String accountName = params.getString("accountName");    //账户名
        String accountNo = params.getString("accountNo");               //账户号
        String province = params.getString("province");                       //开户行所在省
        String city = params.getString("city");                                          //开户行所在市
        String sign = params.getString("sign"); 				                         // 签名
        String remark = params.getString("remark"); 				             // 备注

        // 验证请求参数有效性（必选项）
        Long infoIdL;
        if(StringUtils.isBlank(infoId) || !NumberUtils.isDigits(infoId)) {
            errorMessage = "参数[infoId]必填,且为数值类型.infoId=" + infoId;
            return errorMessage;
        }

        infoIdL = Long.parseLong(infoId);

        if(!NumberUtils.isDigits(settAmount)) {
            errorMessage = "请求参数[settAmount]应为数值类型.";
            return errorMessage;
        }
        Long settAmountL = Long.parseLong(settAmount);
        if(settAmountL <= 0) {
            errorMessage = "请求参数[settAmount]必须大于0.";
            return errorMessage;
        }

        if(StringUtils.isBlank(accountName)) {
            errorMessage = "参数[accountName]账户名，必填";
            return errorMessage;
        }

        if(StringUtils.isBlank(accountNo)) {
            errorMessage = "参数[accountNo]账户名，必填";
            return errorMessage;
        }

        if(StringUtils.isBlank(mchOrderNo)) {
            errorMessage = "参数[mchOrderNo]结算订单编号，必填";
            return errorMessage;
        }

        if(StringUtils.isBlank(bankName)) {
            errorMessage = "参数[bankName]开户银行，必填";
            return errorMessage;
        }

        if(StringUtils.isBlank(bankNetName)) {
            errorMessage = "参数[bankNetName]开户银行，必填";
            return errorMessage;
        }

        // 签名信息
        if (StringUtils.isEmpty(sign)) {
            errorMessage = "请求参数[sign]不能为空.";
            return errorMessage;
        }

        // 查询商户信息
        MchInfo mchInfo = commonService.mchInfoService.findByMchId(infoIdL);
        if(mchInfo == null) {
            errorMessage = "商户不存在.infoId=" + infoId;
            return errorMessage;
        }
        if(mchInfo.getStatus() != MchConstant.PUB_YES) {
            errorMessage = "商户状态不可用.infoId=" + infoId;
            return errorMessage;
        }

        String key = mchInfo.getPrivateKey();
        if (StringUtils.isBlank(key)) {
            errorMessage = "商户私钥为空,请配置商户私钥[infoId="+infoId+"].";
            return errorMessage;
        }
        settContext.put("key", key);
        // 验证签名数据
        boolean verifyFlag = XXPayUtil.verifyPaySign(params, key);
        if(!verifyFlag) {
            errorMessage = "Verify XX pay sign failed.";
            return errorMessage;
        }


        // 得到商户每笔代付手续费
        Long settFee = null;
        if(mchInfo.getFeeType() == 1) {
            settFee = new BigDecimal(settAmountL).multiply(mchInfo.getFeeRate()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP).longValue();
        }else if(mchInfo.getFeeType() == 2) {
            settFee = Long.valueOf(mchInfo.getFeeLevel());
        }
        if(settFee == null) {
            errorMessage = "该商户结算手续费错误.infoId=" + infoId;
            return errorMessage;
        }

        // 验证参数通过,返回JSONObject对象
        SettRecord settRecord = new SettRecord();
        settRecord.setInfoId(infoIdL);
        settRecord.setInfoType(MchConstant.SETT_INFO_TYPE_MCH);
        settRecord.setSettType((byte) 1);
        settRecord.setSettDate(new Date());
        settRecord.setSettAmount(settAmountL);
        settRecord.setSettFee(settFee);
        settRecord.setBankName(bankName);
        settRecord.setBankNetName(bankNetName);
        settRecord.setAccountName(accountName);
        settRecord.setAccountNo(accountNo);
        settRecord.setProvince(province);
        settRecord.setCity(city);
        settRecord.setAccountType(accountType);
        settRecord.setRemark(remark);
        settRecord.setMchOrderNo(mchOrderNo);
        settRecord.setSettChannel(MchConstant.SETT_CHANNEL_API);

        return settRecord;
    }

    @RequestMapping(value = "/api/sett/notify")
    public String notify(HttpServletRequest request) {
        System.out.println("---------------------------------------------"+request.getParameter("id"));
        return null;
    }

}
